#!/usr/sbin/rsct/perl5/bin/perl 
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 1999,2002 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 
# "@(#)64   1.14   src/rsct/registry/cli/bin/repsrfile.perl, srcli, rsct_rpyxh, rpyxht1f3 2/22/01 16:25:47"
######################################################################
#                                                                    #
# Module: repsrfile                                                  #
#                                                                    #
# Purpose:                                                           #
#   repsrfile - Replaces a file stored in the System Registry.       #
#                                                                    #
# Syntax:                                                            #
#   repsrfile [-h][-TV] AIX_filename [SR_filename]                   #
#                                                                    #
# Flags:                                                             #
#   -h Help. Writes this command's usage statement to stdout.        #
#   -T Trace. Writes this command's trace messages to stderr.        #
#   -V Verbose. Writes this command's verbose messages to stderr.    #
#                                                                    #
# Operands:                                                          #
#   AIX_filename    The name of the file to place in the System      #
#                   Registry. An absolute or relative file name can  #
#                   be specified.                                    #
#                                                                    #
#   SR_filename     Optional. The name of the table containing the   #
#                   file to be overwritten in the System Registry.   #
#                   This operand can contain an absolute or relative #
#                   path name. If a relative name is used, the       #
#                   CT_SR_HOME environment variable needs to be set  #
#                   unless the table exists at the root level.       #
#                   Zero or one SR_filename operands can be specified#
#                                                                    #
# Description:                                                       #
#   The repsrfile command overwrites an existing file stored in the  #
#   System Registry with the contents of a new input file, given as  #
#   AIX_filename. If no SR_filename is given, it is assumed to be    #
#   the same name as the input file with the AIX path stripped off   #
#   and the System Registry current working directory added on.      #
#   (See the srcli man page for CT_SR_HOME information on            #
#   how to set the current working directory for the System          #
#   Registry.)                                                       #
#                                                                    #
#   Use the pwdsr command to check the current working directory.    #
#                                                                    #
#   If the AIX_filename does not contain an absolute path, the       #
#   current AIX working directory is selected as the source          #
#   directory for the file.                                          #
#                                                                    #
# Exit Values:                                                       #
#   0  SR_CLI_SUCCESS        Command completed successfully.         #
#   1  SR_CLI_REGISTRY_ERROR Command terminated due to an underlying #
#                            System Registry error.                  #
#   2  SR_CLI_ERROR          Command terminated due to an underlying #
#                            error in the command script.            #
#   3  SR_CLI_BAD_OPERAND    Command terminated due to user          #
#                            specifying a bad operand.               #
#   4  SR_CLI_BAD_FLAG       Command terminated due to user          #
#                            specifying an invalid flag.             #
#   5  SR_CLI_USER_ERROR     Command terminated due to a user error. #
#                            For example specifying an undefined     #
#                            file (table) to be replaced.            #
#                                                                    #
# Examples:                                                          #
#   1. To replace a file stored in the system registry table         #
#   filetable with an AIX file next_file when CT_SR_HOME is set to   #
#   /samples, enter:                                                 #
#        repsrfile next_file filetable                               #
#                                                                    #
#   2. To replace a file stored in the system registry table         #
#   /samples/next_table with an AIX_file next_table when CT_SR_HOME  #
#   is set to /samples, enter:                                       #
#        repsrfile next_file                                         #
#   Note: This provides an easy way to store changes into a          #
#                                                                    #
#--------------------------------------------------------------------#
# Inputs:                                                            #
#                                                                    #
# Outputs:                                                           #
#   stdout - messages during execution and Verbose output            #
#   stderr - error messages                                          #
#                                                                    #
# External Ref:                                                      #
#   Commands: $LSMSG                                                 #
#   Extensions:  CT::SR.pm CT::SRrc.pm CT::CT.pm                     #
#   Perl library routines: Getopts::Std                              #
#   SR cli routines: : SR_cli_utils.pm - init_session, isRelative    #
#                                    printCEMsg,                     #
#                                    open_table, clean_session,      #
#                                    set_session_variables           #
#                                                                    #
# Tab Settings:                                                      #
#   4 and tabs should be expanded to spaces before saving this file. #
#   in vi:  (:set ts=4  and   :%!expand -4)                          #
#                                                                    #
# Change Activity:                                                   #
#   000929 HGJ 38317: Initial delivery.                              #
#                                                                    #
######################################################################

#--------------------------------------------------------------------#
#                                                                    #
# General Program Flow/Logic:                                        #
#                                                                    #
# A: Parse command line - get AIX and SR file name, parse flags      #
# B: Initialise session with registry, including changing the        #
#    current directory if a relative path name is given (use value   #
#    given in CT_SR_HOME)                                            #
# C: Set up the SR file(table) name and AIX filename to open the     #
#    table and store the new data.                                   #
# C: Open table to be edited - exit if it won't open                 #
# D: Store the new file name and data using CT::SR::set_fields_by_key#
# E: Close session table and tree                                    #
#                                                                    #
#--------------------------------------------------------------------#


#--------------------------------------------------------------------#
# Included libraries and extensions                                  #
#--------------------------------------------------------------------#
use lib "/usr/sbin/rsct/pm";
use locale;
use Getopt::Std;
use Cwd;                             # For retrieving the current AIX
                                     #  working directory

use CT::CT qw(:ct_data_type_t);
use CT_cli_utils qw(printIMsg
                    printEMsg
);

use CT::SRrc;
use CT::SR;
use CT::SR qw(:sr_qualifier_t);
use SR_cli_utils qw(init_session 
                    isRelative 
                    printCEMsg 
                    printCIMsg
                    $DEFAULT_GLOBAL_MOUNT_POINT
                    open_table  
                    clean_session
                    error_exit
); 
use SR_cli_rc qw(:return_codes);


#--------------------------------------------------------------------#
# Global Variables                                                   #
#--------------------------------------------------------------------#
# Global constant values 
$TRUE           = 1;
$FALSE          = 0;

$Verbose        = $FALSE;               # set if -V used (see $opt_V)
$Trace          = $FALSE;               # set if -T used (see $opt_T)

# Messaging variables
$PROGNAME       = "repsrfile";           # Program Name for messages
$MSGCAT         = "srcli.cat";           # msg catalogue for this cmd
$CTDIR          = "/usr/sbin/rsct";      # Cluster directory path
$CTBINDIR       = "$CTDIR/bin";          # Cluster Bin directory path
$LSMSG          = "$CTBINDIR/ctdspmsg";  # Display message routine
$ENV{'MSGMAPPATH'} = "$CTDIR/msgmaps";   # Msg maps path for $LSMSG  

%Cleanup = ();                           # Hash of items to cleanup
                                         # {Session} $session to term

#--------------------------------------------------------------------#
# Variables                                                          #
#--------------------------------------------------------------------#
# Variables for use with extensions
my $Table_handle   = "";                 # initialised in open_table
my $Tree_handle    = "";                 # initialised in init_session
my @Column_names   = ();
my @New_fields     = ();
my @Field_types    = ();
my @Field_values   = ();

# Other variables
my $Table_name     = "";
my $AIX_filename   = "";
my $SR_filename    = "";
my $Input_filename = "";

my $Mount_point    = $DEFAULT_GLOBAL_MOUNT_POINT;
my $Buf            = "";
my $Buffer         = "";

my $Set_work_dir   = $FALSE;
my $rc             = 0;                  # assume good return code


#--------------------------------------------------------------------#
# Main Code                                                          #
#--------------------------------------------------------------------#
# TODO: Security on access to the table can not be further defined
# until after a security design has been implemented for the SR.
# ( feature 48402 ) Until then, the table is opened with the
# minimum security necessary to complete the command.
# TODO: Verbose messages in this routine that aren't using message
# maps are trace statements. When trace facilities are available to
# the SR these will be changed. (feature 48401)

# Parse the command line, exit if there are errors
($rc, $AIX_filename, $SR_filename ) = parse_cmd_line();
($rc == 0) || error_exit($rc);  

if ($Verbose) {
    $Command_line_input = "\"  $SR_filename\n  $AIX_filename\n\"";
    printIMsg("IMsgrepsrfileCommandLineInput", $Command_line_input);
}

# Check to make sure the input file exists
if (!(-e $AIX_filename)) {
    printCEMsg("EMsgSRcliInvalidFileName", $AIX_filename);
    $rc = SR_CLI_BAD_OPERAND;
    error_exit($rc);
}

# Initialize variables for init_session - check to see if an
# absolute or relative table name has been passed in.

# $SR_filename not existing or being relative is the
# minimal condition for setting the current working
# directory in the registry. Given this, the library
# connection can be established

if (($SR_filename eq "") or (isRelative($SR_filename))) {
    $Set_work_dir= $TRUE;
}


# Get the table name ready for passing to CT::SR::open_table
if ($SR_filename eq "") {
    $Table_name = $AIX_filename;
    $Table_name =~ s/^.*(.*)$/$1/;

    # Save the table name without the mount point for messaging
    $SR_filename = $Table_name;

    $Table_name = $Mount_point.$Table_name;
}
else {
    if (isRelative($SR_filename)) {
        $Table_name = $SR_filename;
    }
    else {$Table_name = $Mount_point.$SR_filename;}
}


# Get the absolute path of the AIX filename ready to be stored
if (isRelative($AIX_filename)) {
    # Get the absolute path from cwd() - it will need
    # to be stored in the registry table

    # From the Cwd package - with base Perl 5 - p 386, Camel
    $AIX_working_directory = cwd();
    $Input_filename = $AIX_working_directory.'/'.$AIX_filename;
}


# When the 'pack' problem for binary files (see reference in mksrfile)
# is solved, this code may be uncommented in part.
#if (-B $AIX_filename) {
#        printEMsg("EMsgrepsrfileBinaryFile", $AIX_filename);
#        exit SR_CLI_BAD_OPERAND;
#   $is_binary = $TRUE;
#}


# Open the input filename and pull in the file
# 'open' supports ../, ./ and so forth, so $AIX_filename is
# used as is comes from the command line.
if (!open(FH, $AIX_filename)) {
    printEMsg("EMsgSRcliCannotOpenFile", $AIX_filename);
    $rc = SR_CLI_BAD_OPERAND;
    error_exit($rc); 
}


# Read the file contents into a buffer - how big can this be?
# How do I read it all in at once?
$count = 0;
$Buf = "";
while (read(FH, $Buffer, 8 * 2**10)) {
    $count++;
    $Buf .= $Buffer;
}

# Convert the input to binary. Assume ascii unless otherwise
# mentioned? - Start with Ascii at any rate

# TODO: for now, the "B*" unpack wants to even out an odd number
# of bytes, so binary is packed as ascii. (which doesn't really
# pack it at all.)
# The corresponding unpack trims off newline characters.
#$Binary_image = pack("A*", $Buf);
#$Binary_image = pack("B*", $Buf);

# Take the length of $Binary_image as the length to be stored
# in the System Registry

$Binary_image = $Buf;
$Packed_length = length($Binary_image);
$Verbose && print STDERR "packed length: $Packed_length\n";


# This is late in the stream, but prior to this everything is
# dealing with AIX

# Initialize Registry Library Connection
($rc,$Tree_handle) = init_session($Set_work_dir);
($rc == 0) || error_exit($rc);  

# Add tree handle to cleanup hash
$Cleanup{Session} = $Tree_handle;


$Verbose && printIMsg("IMsgrepsrfileReplacingFile", $SR_filename, 
                        $Table_name);


# Call CT::SR::open_table to open table to be edited 
($rc, $Table_handle) = open_table($Tree_handle, $Table_name, 
                        $SR_filename, SR_WRITE);
($rc == 0) || error_exit($rc);  

# Add table handle to cleanup hash
push @{$Cleanup{Tables}} , $Table_handle;


# Get the file statistics for the new file
($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size,
    $atime, $mtime, $ctime, $blksize, $blocks) = stat FH;

# Extract the uid, gid from the mode information
($s, $user, $group, $other) = (($mode & 07000)>>9, ($mode & 0700)>>6, ($mode & 0070)>>3, $mode & 0007);

# Compile the permissions (binary form)
$permissions = $s.$user.$group.$other;
$Verbose && print STDERR "permissions: $permissions\n";


# Set up the column names to be altered and the fields containing 
# the new file data
@Column_names = ("FileName", "ModificationDate", "LastAccessDate",
                "Permissions", "UID", "GID", "Type", "FileData");   

# Set up the data fields

$Field_values[0] = $Input_filename;
$Field_values[1] = $mtime;
$Field_values[2] = $atime;
$Field_values[3] = $permissions;
$Field_values[4] = $uid;
$Field_values[5] = $gid;

#if ($is_binary) { $Field_values[6] = "binary"; }
#else { $Field_values[6] = "text";}
$Field_values[6] = "text";

%Binary_hv = ("length" => $Packed_length,
            "image" => $Binary_image
);

$Field_values[7] = \%Binary_hv;


# Set up the field types array - list of the data type of each field
@Field_types = (CT_CHAR_PTR, CT_CHAR_PTR, CT_CHAR_PTR, 
                CT_CHAR_PTR, CT_CHAR_PTR, CT_CHAR_PTR, 
                CT_CHAR_PTR, CT_BINARY_PTR
);

# Set up the row key to be used - the row key number is
# assigned in mksrfile, hard coded. 

%Row_key = ("type" => CT_UINT32,
            "value" => 2001
);

@New_fields = ([@Field_values], [@Field_types], 8);

# Call extension to change/set the field values
# and 'replace the file'
$Trace && print STDERR "Calling CT::SR::set_fields_by_key\n";
$rc = CT::SR::set_fields_by_key($Table_handle, \%Row_key, 
                        \@Column_names, \@New_fields );
$Trace && print STDERR "CT::SR::set_field_by_key return code: $rc\n";

# Check the result of CT::SR::set_fields_by_key
# The error conditions checked for here are limited because
# the extent of the user's responsibility. All other codes
# are captured under the generic error message.
$rc = error_check("sr_set_fields_by_key", $rc, $SR_filename);
($rc == 0) || error_exit($rc);

# Clean session up and exit
$rc = clean_session($Tree_handle, $Mount_point, $Table_handle);
# Error messages handled in init_session

# Clear cleanup hash to clean_session isn't executed in error_exit
%Cleanup = ();
($rc == 0) || error_exit($rc);  

# Return code is 0 here.
exit $rc;

#--------------------------------------------------------------------#
# End Main Code                                                      #
#--------------------------------------------------------------------#


#--------------------------------------------------------------------#
# parse_cmd_line:                                                    #
#   Uses getopts() to grab flags on the command line                 #
#                                                                    #
# Parameters: none.                                                  #
#                                                                    #
# Return values:                                                     #
#   $local_rc - local return code                                    #
#   $AIX_file - AIX file name to be stored in the System Registry    #
#   $SR_file - table name to use to store the file                   #
#                                                                    #
# Global variables modified:                                         #
#   $opt_h, $opt_V - by getopts                                      #
#   $Verbose - if $opt_V is set                                      #
#   $Trace - if $opt_T is set                                        #
#   @ARGV - input collected from this array                          #
#                                                                    #
#--------------------------------------------------------------------#
sub parse_cmd_line
{
my $local_rc = 0;
my $AIX_file = "";
my $SR_file  = "";
my %opts = ();

if (getopts('hTV', \%opts) == 0) {      # parse input flags
    printCEMsg("EMsgSRcliInvalidFlag");
    print_usage();
    return SR_CLI_BAD_FLAG;             # error parsing command line
}

if (defined $opts{h}) {                 # print usage and exit
    print_usage();
    exit(0);                            # success but quit
}

# Set the Trace flag if requested
if (defined $opts{T}) {
    $Trace = $TRUE;
}

# Set the Verbose flag if requested
if (defined $opts{V}) {
    $Verbose = $TRUE;
}

# Grab the AIX filename, if there
if (@ARGV) { 
    $AIX_file = shift @ARGV;
}
else {
    printCEMsg("EMsgSRcliFileNameMissing");
    print_usage();
    return SR_CLI_BAD_OPERAND;
}

# Grab the optional SR table name
if (@ARGV) { $SR_file = shift @ARGV; }
else { $SR_file = ""; }

return ($local_rc, $AIX_file, $SR_file);
}   # end parse_cmd_line


#--------------------------------------------------------------------#
# error_check:                                                       #
#   Checks the return code from the SR function.  If an error is     #
#   detected appropriate error messages will be displayed and        #
#   SR CLI return code set.                                          #
#                                                                    #
# Parameters:                                                        #
#   $sr_function  - Name of the SR function that was called and      #
#                   whose error code we are checking.                #
#   $sr_rc        - SR function return code.                         #
#   $sr_filename  - Name of the table in the SR that contains the    #
#                   file that is to be overwritten.                  #
#                                                                    #
# Return values:                                                     #
#   None.                                                            #
#                                                                    #
# Global References:                                                 #
#   None.                                                            #
#--------------------------------------------------------------------#
sub error_check
{
my ($sr_function, $sr_rc, $sr_filename) = @_;
my $rc = 0;

if ($sr_rc != 0){
    if ($sr_rc == SR_NO_PERMISSION) {
        printEMsg("EMsgrepsrfileNoPermission", $sr_filename);
        $rc = SR_CLI_USER_ERROR;
    }
    elsif ($sr_rc == SR_NO_TABLE) {
        printEMsg("EMsgrepsrfileNoTable", $sr_filename);
        $rc = SR_CLI_USER_ERROR;
    }
    else {
        printEMsg("EMsgrepsrfileErrorReplacingFile", $sr_filename);
        printCEMsg("EMsgSRcliSRCommandFailure", $sr_function, $sr_rc);
        $rc = SR_CLI_REGISTRY_ERROR;
    }
}

return ($rc);
}   # end error_check


#--------------------------------------------------------------------#
# print_usage : print the usage statement (syntax) to stdout.        #
#   See this command's prologue syntax section for current usage.    #
#--------------------------------------------------------------------#
sub print_usage
{
printIMsg("IMsgrepsrfileUsage");
} # end print_usage


#--------------------------------------------------------------------#
# End File                                                           #
#--------------------------------------------------------------------#
